Cryptography 를 이용한 인증서 정보 추출
Cryptography 모듈을 호출하여 인증서 내용을 불러오는 것으로 시작한다.
-
아래의 loadpemx509_certificate()를 통해서 인증서의 정보를 가져올 수 있다.
from cryptography import x509 from cryptography.hazmat.backends import default_backend cert_pem = "인증서의 내용" cert = x509.load_pem_x509_certificate(cert_pem, default_backend())
-
인증서 Version 확인
# 위의 코드에서부터 연결되어 내려온다. cert.version
-
인증서 Fingerprint
from cryptography.hazmat.primitives import hashes # 암호화 타입에 따라서 fingerprint의 정보는 달라짐., # browser에서 인증서 정보를 보면 fingerprint의 암호화 타입도 같이 확인이 됨 fingerprint = cert.fingerprint(hashes.SHA1()) fingerprint = fingerprint.encode('hex')
-
serial_number
# 인증서의 serial number 를 가져온다 cert.serial_number # 단, browser에서 표시되는 인증서 정보에서의 값과 유사하게 만들어 주기 위해서는 아래의 추가 작업이 필요하다. serial = hex(cert.serial_number) serial = serial.rstrip("L").lstrip("0x") serial = serial.zfill(34) serial_list = [serial[s:s+2] for s in range(0, len(serial), 2)]
-
인증서 등록일자
cert.not_valid_before
-
인증서 만료일자
cert.not_valid_after
-
인증서의 도메인 추출
from cryptography.x509.oid import NameOID cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
-
인증서 발급기관 추출
from cryptography.x509.oid import NameOID cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
-
public key 추출
from cryptography.hazmat.primitives import serialization # 인증키를 통해서 public-key를 추출한다. public_key = cert.public_key() pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo )
-
Private key 인증서를 가져오는 방법
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization private_key_pem = "개인 키 내용" private_key = serialization.load_pem_private_key( private_key_pem, password=None, backend=default_backend() )
OpenSSL 모듈을 이용한 인증서 검증
OpenSSL 모듈을 이용하여 인증서와 개인키의 유효성 검증 및 체인 키와 인증서의 유효성 검증을 진행한다.
-
기본적인 모듈 호춢 및 인증서들에 대한 변수선언을 아래와 같이 해준다.
import OpenSSL certificate = "인증서 내용" private_key = "개인 키 내용" chain_auth_key = "체인키 내용"
-
인증서와 개인 키간의 검증 과정
# 개인키와 인증서를 OpenSSL의 객체로 생성 pk_obj = OpenSSL.crypto.load_privatekey(crypto.FILETYPE_PEM, private_key) cert_obj = OpenSSL.crypto.load_certificate(crypto.FILETYPE_PEM, certificate) # Context 객체에 인증키와 개인키를 입력 한 후 check context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD) context.use_privatekey(pk_obj) context.use_certificate(cert_obj) # 인증서와 개인키가 서로 유효한 경우 error 발생하지 않음 try: context.check_privatekey() except OpenSSL.SSL.Error as err: print("do not match")
일부 인증서의 경우 인증서를 발급받은 기관에 따라서 올바르지 않은 인증서라고 나오는 경우가 있는데, 이러한 문제를 해결하기 위해서 체인 인증서
를 추가로 등록한다.
아래의 경우는 그 체인 인증서
가 올바른지 인증하기 위한 검토 logic 이다.
해당 내용은 해당 링크를 참조하였다.
-
인증서와 Chain Key간의 검증
import re # Chain Key의 경우 여러개의 인증서 내용이 연달아 있으므로 인증서들의 유효성 및 List 형태로 분리을 위한 # regular expression을 이용하여 처리 PEM_RE = re.compile(b'-----BEGIN CERTIFICATE-----\r?.+?\r?-----END CERTIFICATE-----\r?\n?', re.DOTALL) # Chain Key에서 인증서내용들을 List 타입으로 분리 def parse_chain(chain): return [c.group() for c in PEM_RE.finditer(chain)] store = OpenSSL.crypto.X509Store() try: # 분리한 key 값들을 store에 저장. # store에 인증서 등록시에 인증서의 방식(type, encode)이 잘못된 경우 error 발생 for cr in parse_chain(chain_auth_key): store.add_cert(OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cr)) except OpenSSL.crypto.Error as err: print("Encode Type Error") # store에 등록된 인증서들과 certificate를 비교하기 위한 context 객체 생성 context = OpenSSL.crypto.X509StoreContext(store, cert_obj) try: # verify_certificate method를 이용하여 유효성 검증 context.verify_certificate() except OpenSSL.crypto.X509StoreContextError as err: print("unable to get local issuer certificate")